const { result } = require("lodash")
const { resolve } = require("../../../../../课程/01-01-study-materials/01-01-codes/01-01-03-01-my-promise/myPromise")

/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
const PENDING = 'pending' // 等待状态
const FULFILLED = 'fulfilled' // 成功状态
const REJECTED = 'rejected' // 失败状态

class MyPromise {
  status = PENDING  // promsie 状态 
  value = undefined  // 成功后的值
  reason = undefined  // 失败后的原因
  fulfilledCallback = []  // 成功回调函数
  rejectedCallback = []  // 失败回调函数

  constructor (executor) {
    try {
      executor(this.resolve, this.reject)  // 调用执行器
    } catch (e) {
      this.reject(e)
    }
  }

  resolve = value => {
    if (this.status !== PENDING) return  // 判断 promise 状态是否时等待
    this.status = FULFILLED  // 修改为成功状态
    this.value = value  // 保存成功的值
    // 判断是否有成功回调，如果有 执行回调
    while (this.fulfilledCallback.length) this.fulfilledCallback.shift()()
  }

  reject = reason => {
    try {
      if (this.status !== PENDING) return  // 判断 promise 状态是否是等待
      this.status = REJECTED  // 修改为失败状态
      this.reason = reason  // 保存失败原因
      // 判断是否有失败回调，如果有 执行回调
      if (this.rejectedCallback.length === 0) throw this.reason
      while (this.rejectedCallback.length) this.rejectedCallback.shift()()
    } catch (e) {
      console.error(e.name + ': ' + e.message)
    }
  }

  then (fulfilledCallback, rejectedCallback) {
    // 参数可选
    fulfilledCallback = fulfilledCallback ?  fulfilledCallback : value => value
    rejectedCallback = rejectedCallback ? rejectedCallback : reason => { throw reason }
    let promise2 = new MyPromise((resolve, reject) => {
      // 判断状态
      if (this.status === FULFILLED) {  // 成功状态
        setTimeout(() => {
          try{
            let x = fulfilledCallback(this.value)  // 执行成功回调并保存返回值
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else if (this.status == REJECTED) {  // 失败状态
        setTimeout(() => {
          try{
            let x = rejectedCallback(this.reason)  // 执行失败回调并保存返回值
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else {  // 等待状态
        this.fulfilledCallback.push(() => {  // 保存成功回调
          setTimeout(() => {
            try{
              let x = fulfilledCallback(this.value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
        this.rejectedCallback.push(() => {  // 保存失败回调
          setTimeout(() => {
            try{
              let x = rejectedCallback(this.reason)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
      }
    })
    return promise2
  }

  /**
   * 不管成功还是失败都执行
   * @param {Function} callback 
   * @returns promise 对象
   */
  finally (callback) {
    return this.then(value => {
      return MyPromise.resolve(callback()).then(() => value)  // 如果callback的返回值是 promise 对象 则等待promsie对象的结果 并将value传递下去
    }, reason => {
      return MyPromise.resolve(callback()).then(() => { throw reason })  // 同上
    })
  }

  catch (rejectedCallback) {
    return this.then(undefined, rejectedCallback)
  }

  static all (array) {
    let result = []  // 定义一个数组，最终的promise对象会resolve这个
    let index = 0  // 用来判断是否等于array.length
    return new MyPromise((resolve, reject) => {
      function addData (key, value) {
        result[key] = value
        index++
        // 判断array的所以结果是否存储在result，如果是则执行成功回调
        if (index === array.length) resolve(result)
      }
      // 循环array
      for (let i = 0; i < array.length; i++) {
        let current = array[i]
        // 判断是否是promise对象
        if (current instanceof MyPromise) {  // 如果是，则查看promise返回结果并将结果存储在result
          current.then(value => addData(i, value), reject)
        } else {  // 如果是普通值，则将值存储在result
          addData(i, current)
        }
      }
    })
  }

  static resolve (value) {
    // 如果value是promise对象，则直接返回value
    if (value instanceof MyPromise) return value
    // 如果value是普通值，则将value包裹一层promise返回
    return new MyPromise(resolve => resolve(value))
  }
}


/**
 * 判断 x 的值是普通值还是promise对象
 * 如果是普通值 直接调用resolve
 * 如果是promise对象 查看promsie对象返回的结果
 * 再根据promise对象返回的结果 决定调用resolve 还是调用reject
 * @param {*} promise2 
 * @param {*} x 
 * @param {*} resolve 
 * @param {*} reject 
 * @returns 
 */
function resolvePromise (promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (x instanceof MyPromise) {
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}

const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(100)
  }, 1000)
})

const p1 = promise.then(res => {
  return p1
})

module.exports = MyPromise